/*
  VitaShell
  Copyright (C) 2015-2018, TheFloW

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "main.h"
#include "ime_dialog.h"
#include "utils.h"

static int ime_dialog_running = 0;
static int ime_dialog_option = 0;

static const char *ime_initial_text = NULL;
static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH];
static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH];
static uint16_t ime_input_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1];
static uint8_t ime_input_text_utf8[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1];

static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) {
  int i;
  for (i = 0; src[i]; i++) {
    if ((src[i] & 0xFF80) == 0) {
      *(dst++) = src[i] & 0xFF;
    } else if((src[i] & 0xF800) == 0) {
      *(dst++) = ((src[i] >> 6) & 0xFF) | 0xC0;
      *(dst++) = (src[i] & 0x3F) | 0x80;
    } else if((src[i] & 0xFC00) == 0xD800 && (src[i + 1] & 0xFC00) == 0xDC00) {
      *(dst++) = (((src[i] + 64) >> 8) & 0x3) | 0xF0;
      *(dst++) = (((src[i] >> 2) + 16) & 0x3F) | 0x80;
      *(dst++) = ((src[i] >> 4) & 0x30) | 0x80 | ((src[i + 1] << 2) & 0xF);
      *(dst++) = (src[i + 1] & 0x3F) | 0x80;
      i += 1;
    } else {
      *(dst++) = ((src[i] >> 12) & 0xF) | 0xE0;
      *(dst++) = ((src[i] >> 6) & 0x3F) | 0x80;
      *(dst++) = (src[i] & 0x3F) | 0x80;
    }
  }

  *dst = '\0';
}

static void utf8_to_utf16(const uint8_t *src, uint16_t *dst) {
  int i;
  for (i = 0; src[i];) {
    if ((src[i] & 0xE0) == 0xE0) {
      *(dst++) = ((src[i] & 0x0F) << 12) | ((src[i + 1] & 0x3F) << 6) | (src[i + 2] & 0x3F);
      i += 3;
    } else if ((src[i] & 0xC0) == 0xC0) {
      *(dst++) = ((src[i] & 0x1F) << 6) | (src[i + 1] & 0x3F);
      i += 2;
    } else {
      *(dst++) = src[i];
      i += 1;
    }
  }

  *dst = '\0';
}

int initImeDialog(const char *title, const char *initial_text, int max_text_length, int type, int option, int password) {
  if (ime_dialog_running)
    return VITASHELL_ERROR_ALREADY_RUNNING;

  ime_initial_text = initial_text;

  // Convert UTF8 to UTF16
  memset(ime_title_utf16, 0, sizeof(ime_title_utf16));
  memset(ime_initial_text_utf16, 0, sizeof(ime_initial_text_utf16));
  utf8_to_utf16((uint8_t *)title, ime_title_utf16);
  utf8_to_utf16((uint8_t *)initial_text, ime_initial_text_utf16);

  SceImeDialogParam param;
  sceImeDialogParamInit(&param);

  param.supportedLanguages = 0x0001FFFF;
  param.languagesForced = SCE_TRUE;
  param.type = type;
  param.option = option;
  if (option == SCE_IME_OPTION_MULTILINE)
    param.dialogMode = SCE_IME_DIALOG_DIALOG_MODE_WITH_CANCEL;
  param.textBoxMode = password ? SCE_IME_DIALOG_TEXTBOX_MODE_PASSWORD : SCE_IME_DIALOG_TEXTBOX_MODE_DEFAULT;
  param.title = ime_title_utf16;
  param.maxTextLength = max_text_length;
  param.initialText = ime_initial_text_utf16;
  param.inputTextBuffer = ime_input_text_utf16;

  int res = sceImeDialogInit(&param);
  if (res >= 0) {
    ime_dialog_running = 1;
    ime_dialog_option = option;
  }

  return res;
}

int isImeDialogRunning() {
  return ime_dialog_running;  
}

uint16_t *getImeDialogInputTextUTF16() {
  return ime_input_text_utf16;
}

uint8_t *getImeDialogInputTextUTF8() {
  return ime_input_text_utf8;
}

const char *getImeDialogInitialText() {
  return ime_initial_text;
}

int updateImeDialog() {
  if (!ime_dialog_running)
    return IME_DIALOG_RESULT_NONE;

  SceCommonDialogStatus status = sceImeDialogGetStatus();
  if (status == IME_DIALOG_RESULT_FINISHED) {
    SceImeDialogResult result;
    memset(&result, 0, sizeof(SceImeDialogResult));
    sceImeDialogGetResult(&result);

    if ((ime_dialog_option == SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_CLOSE) ||
        (ime_dialog_option != SCE_IME_OPTION_MULTILINE && result.button == SCE_IME_DIALOG_BUTTON_ENTER)) {
      // Convert UTF16 to UTF8
      utf16_to_utf8(ime_input_text_utf16, ime_input_text_utf8);
    } else {
      status = IME_DIALOG_RESULT_CANCELED;
    }

    sceImeDialogTerm();

    ime_dialog_running = 0;
  }

  return status;
}
